#ifndef RULE_H
#define RULE_H

//#define DEBUGLEXER

#ifdef DEBUGLEXER
#include <string>
#include <iostream>
#endif

#include "parsestream.h"

template<typename T>
class scoped_ptr {
	public:
		explicit scoped_ptr(T * p = 0): ptr(p) { }
		
		~scoped_ptr() {
			delete ptr;
		}
		
		void reset(T * p = 0) {
			ptr = p;
		}
		
		T & operator*() const { return *ptr; }
		
		T * operator->() const { return ptr; }
		
		T * get() const { return ptr; }
		
		operator bool () const { return ptr != 0; }
		
	private:
		scoped_ptr(scoped_ptr const &) { }
		scoped_ptr & operator=(scoped_ptr const &) { }
		
		T *ptr;
};

class AbstractSingleRule {
	public:
		AbstractSingleRule() {};
		//virtual ~AbstractSingleRule() {};
		virtual bool recognize(ParseStream*) { return true; } //= 0;
};

template<typename T>
class SingleRule : public AbstractSingleRule {
	public:
		SingleRule(T const& _prs) : prs(_prs) { }
		
		/*inline */bool recognize(ParseStream* x) {
			return prs.recognize(x);
		}
		
		inline char* get(ParseStream* x) { return prs.get(x); }
		
		
	private:
		T prs;
};

template<typename T = AbstractSingleRule>
class Rule {
	public:
		Rule() { }
		//~Rule() { delete rule; }
		
		template<typename U> explicit Rule(U const& r) : rule(new SingleRule<U>(r)) { }
	
		template<typename U> Rule(U* r) : rule(r) { }
	
		inline T* get() { return rule; }
		
		//Rule(Rule const& r) { rule = new SingleRule< Rule >(r); }
		
		template<typename U> Rule& operator=(U const& r) { rule = new SingleRule<U>(r); return *this; }
	
		bool recognize(ParseStream* x) const {
#ifdef DEBUGLEXER
			std::cout << "Parsing rule: " << namerule << std::endl;
			bool ris = rule->recognize(x);
			//if (ris) std::cout << "Con successo!" << std::endl;
			//else std::cout << "Con insucesso!" << std::endl;
			return ris;
#endif
#ifndef DEBUGLEXER
			return rule->recognize(x);
#endif
		}
		
#ifdef DEBUGLEXER
		void setName(const std::string& _name) {
			namerule = _name;
		}

		std::string getName() const {
			return namerule;
		}
#endif

		typedef Rule<T> const& embed_t;
	private:
		T* rule;
#ifdef DEBUGLEXER
		std::string namerule;
#endif
};

template<typename T, typename U>
class OperatorOr {
	public:
		OperatorOr(T const& _a, U const& _b) : a(_a), b(_b) { }
		
		inline bool recognize(ParseStream* x) {
			return a.recognize(x) || b.recognize(x);
		}
		
		typedef OperatorOr<T, U> embed_t;
	private:
		typename T::embed_t a;
		typename U::embed_t b;
};

template<typename T, typename U>
class OperatorXor {
	public:
		OperatorXor(T const& _a, U const& _b) : a(_a), b(_b) { }
		
		inline bool recognize(ParseStream* x) {
			int i = x->getPosition();
			if (a.recognize(x)) {
				x->setPosition(i);
				if (b.recognize(x)) {
					return false;
				}
				return true;
			}
			else if (b.recognize(x)) {
				return true;
			}
			return false;
		}
		
		typedef OperatorOr<T, U> embed_t;
	private:
		typename T::embed_t a;
		typename U::embed_t b;
};

template<typename T>
class OperatorNot {
	public:
		OperatorNot(T const& _a) : a(_a) { }
		
		inline bool recognize(ParseStream* x) {
			int i = x->getPosition();
			if (a.recognize(x)) {
				x->setPosition(i);
				return false;
			}
			else return true;
		}
		
		typedef OperatorNot<T> embed_t;
	private:
		typename T::embed_t a;
};

template<typename T, typename U>
class OperatorAnd {
	public:
		OperatorAnd(T const& _a, U const& _b) : a(_a), b(_b) { }
		
		inline bool recognize(ParseStream* x) {
			if (a.recognize(x)) {
				x->previous();
				if (b.recognize(x)) {
					return true;
				}
			}
			return false;
		}
		
		typedef OperatorAnd<T, U> embed_t;
	private:
		typename T::embed_t a;
		typename U::embed_t b;
};

template<typename T, typename U>
class OperatorSequence {
	public:
		OperatorSequence(T const& _a, U const& _b) : a(_a), b(_b) { }
		
		inline bool recognize(ParseStream* x) {
			if (a.recognize(x)) {
				if (b.recognize(x)) {
					return true;
				}
				x->previous();
			}
			return false;
		}
		
		typedef OperatorSequence<T, U> embed_t;
	private:
		typename T::embed_t a;
		typename U::embed_t b;
};

template<typename T, typename U = int>
class OperatorMultipleSequence {
	public:
		OperatorMultipleSequence(T const& _a, U const& _b) : a(_a), b(_b) { }
		
		inline bool recognize(ParseStream* x) {
			int j = x->getPosition(), i = 0;
			while (i < b && a.recognize(x)) {
				++i;
			}
			if (i == b) return true;
			else {
				x->setPosition(j);
				return false;
			}
		}
		
		typedef OperatorMultipleSequence<T, U> embed_t;
	private:
		typename T::embed_t a;
		typename U::embed_t b;
};

template<typename T>
class OperatorMultipleStarSequence {
	public:
		OperatorMultipleStarSequence(T const& _a) : a(_a) { }
		
		inline bool recognize(ParseStream* x) {
			while (a.recognize(x)) { }
			return true;
		}
		
		typedef OperatorMultipleStarSequence<T> embed_t;
	private:
		typename T::embed_t a;
};

template<typename T>
class OperatorMultiplePlusSequence {
	public:
		OperatorMultiplePlusSequence(T const& _a) : a(_a) { }
		
		inline bool recognize(ParseStream* x) {
			if (!a.recognize(x)) return false;
			while (a.recognize(x)) { }
			return true;
		}
		
		typedef OperatorMultiplePlusSequence<T> embed_t;
	private:
		typename T::embed_t a;
};

template<typename T>
class OperatorOptional {
	public:
		OperatorOptional(T const& _a) : a(_a) { }
		
		inline bool recognize(ParseStream* x) {
			if (!a.recognize(x)) return true;
			else {
				if (a.recognize(x)) {
					x->previous();
					return false;
				}
				return true;
			}
		}
		
		typedef OperatorOptional<T> embed_t;
	private:
		typename T::embed_t a;
};



template<typename T = char>
class Range {
	public:
		Range(T _a, T _b) : a(_a), b(_b) { }
		
		inline bool recognize(ParseStream* x) {
			if (!x->endstream()) {
				if ((x->get() >= a) && (x->get() <= b)) {
					x->next();
					return true;
				}
			}
			return false;
		}
		
		typedef Range<T> embed_t;
	private:
		T a;
		T b;
};



template<typename T = char>
class Character {
	public:
		Character(T _a) : a(_a) { }
		
		inline bool recognize(ParseStream* x) {
			if (!x->endstream()) {
				if (x->get() == a) {
					x->next();
					return true;
				}
			}
			
			return false;
		}
		
		typedef Character<T> embed_t;
	private:
		T a;
};

template<typename T = char const*>
class String {
	public:
		String(T _a) : a(_a) { }
		
		inline bool recognize(ParseStream* x) {
			int i = 0, j = x->getPosition();
			while (!x->endstream() && a[i] != 0 && x->get() == a[i]) {
				x->next();
				++i;
			}
			if (a[i] == 0) {
				return true;
			}
			else {
				x->setPosition(j);
				return false;
			}
		}
		
		typedef String<T> embed_t;
	private:
		T a;
};


template<typename A, typename B>
inline OperatorOr<A,B> operator||(A const& a, B const& b) {
	return OperatorOr<A,B>(a,b);
}

template<typename A, typename B>
inline OperatorAnd<A,B> operator&&(A const& a, B const& b) {
	return OperatorAnd<A,B>(a,b);
}

template<typename A, typename B>
inline OperatorSequence<A,B> operator>>(A const& a, B const& b) {
	return OperatorSequence<A,B>(a,b);
}

template<typename A, typename B>
inline OperatorXor<A,B> operator^(A const& a, B const& b) {
	return OperatorXor<A,B>(a,b);
}

template<typename A>
inline OperatorMultipleStarSequence<A> operator*(A const& a) {
	return OperatorMultipleStarSequence<A>(a);
}

template<typename A>
inline OperatorMultipleSequence<A> operator*(A const& a, int b) {
	return OperatorMultipleSequence<A>(a,b);
}

template<typename A>
inline OperatorMultiplePlusSequence<A> operator+(A const& a) {
	return OperatorMultiplePlusSequence<A>(a);
}

template<typename A>
inline OperatorOptional<A> operator!(A const& a) {
	return OperatorOptional<A>(a);
}

template<typename A>
inline OperatorNot<A> operator~(A const& a) {
	return OperatorNot<A>(a);
}

#endif
